﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Xml;
using Common.Utilities;
using Common.Utilities.Dispatcher;

namespace Workflows.Components.ETL
{
    /// <summary>
    /// 
    /// </summary>
    [Serializable]
    public class OracleBulkLoadInstruction:InstructionBase
    {
        #region members
        private string _SqlLoaderProgramFilePath;
        /// <summary></summary>
        public string SqlLoaderProgramFilePath
        {
            get
            {
                return this._SqlLoaderProgramFilePath;
            }
            set
            {
                this._SqlLoaderProgramFilePath = value;
            }
        }

        private string _ConnectionString;
        /// <summary></summary>
        public string ConnectionString
        {
            get
            {
                return this._ConnectionString;
            }
            set
            {
                this._ConnectionString = value;
            }
        }

        private string _TableName;
        /// <summary></summary>
        public string TableName
        {
            get
            {
                return this._TableName;
            }
            set
            {
                this._TableName = value;
            }
        }

        private string _SrcDataFilePath;
        /// <summary></summary>
        public string SrcDataFilePath
        {
            get
            {
                return this._SrcDataFilePath;
            }
            set
            {
                this._SrcDataFilePath = value;
            }
        }

        private string _SrcConnStr;
        /// <summary></summary>
        public string SrcConnStr
        {
            get
            {
                return this._SrcConnStr;
            }
            set
            {
                this._SrcConnStr = value;
            }
        }

        private string _SelectSqlStatement;
        /// <summary></summary>
        public string SelectSqlStatement
        {
            get
            {
                return this._SelectSqlStatement;
            }
            set
            {
                this._SelectSqlStatement = value;
            }
        }

        private bool _TruncateTableBeforeInsert;
        /// <summary></summary>
        public bool TruncateTableBeforeInsert
        {
            get
            {
                return this._TruncateTableBeforeInsert;
            }
            set
            {
                this._TruncateTableBeforeInsert = value;
            }
        }

        private FieldDelimiter _FieldDelimiter;
        /// <summary></summary>
        public FieldDelimiter FieldDelimiter
        {
            get
            {
                return this._FieldDelimiter;
            }
            set
            {
                this._FieldDelimiter = value;
            }
        }

        private Dictionary<string,int> _FieldSizes;
        /// <summary></summary>
        public Dictionary<string,int> FieldSizes
        {
            get
            {
                return this._FieldSizes;
            }
            set
            {
                this._FieldSizes = value;
            }
        }

        private List<string> _TableFields;
        /// <summary></summary>
        public List<string> TableFields
        {
            get
            {
                return this._TableFields;
            }
            set
            {
                this._TableFields = value;
            }
        }

        #endregion
        /// <summary></summary>
        public OracleBulkLoadInstruction():base(Guid.Empty,Guid.Empty)
        {
            this._SqlLoaderProgramFilePath = string.Empty;
            this._ConnectionString = string.Empty;
            this._TableName = string.Empty;
            this._SrcDataFilePath = string.Empty;
            this._FieldDelimiter = ETL.FieldDelimiter.Tab;
            this._FieldSizes=new Dictionary<string, int>();
            this._TableFields=new List<string>();

            this._SrcConnStr = string.Empty;
            this._SelectSqlStatement = string.Empty;
            this._TruncateTableBeforeInsert = false;
        }
        /// <summary></summary>
        public OracleBulkLoadInstruction(Guid componentID, Guid jobTicketID,
            string sqlldrFilePath, string connStr, string tblName,
            string dataFilePath, FieldDelimiter delimiter,
            Dictionary<string,int> fieldSizes, List<string> tableFields,
            string srcConnStr, string selectSql, bool truncateTgtTableBeforeLoad)
            : base(componentID, jobTicketID)
        {
            this._SqlLoaderProgramFilePath = sqlldrFilePath;
            this._ConnectionString = connStr;
            this._TableName = tblName;
            this._SrcDataFilePath = dataFilePath;
            this._FieldDelimiter = delimiter;
            this._FieldSizes = fieldSizes;
            this._TableFields = tableFields;

            this._SrcConnStr = srcConnStr;
            this._SelectSqlStatement = selectSql;
            this._TruncateTableBeforeInsert = truncateTgtTableBeforeLoad;
        }

        public override XmlNode Serialize(ref XmlDocument xDoc, ref XmlNode parentNode)
        {
            XmlNode xNode = XmlDataUtil.AddElement(ref xDoc, parentNode, "Instruction");
            XmlDataUtil.UpdateAttribute(ref xDoc, xNode, "Type", this.GetType().FullName);
            XmlDataUtil.UpdateAttribute(ref xDoc, xNode, "ComponentID", this.OwnerComponentID.ToString());
            XmlDataUtil.UpdateAttribute(ref xDoc, xNode, "WorkerID", this.OwnerWorkerInstanceID.ToString());
            XmlDataUtil.UpdateAttribute(ref xDoc, xNode, "SubmitTime", this.SubmitTime.ToString());
            XmlDataUtil.UpdateAttribute(ref xDoc, xNode, "StartTime", this.StartTime.ToString());

            XmlDataUtil.UpdateAttribute(ref xDoc,xNode,"SqlldrFilePath",this.SqlLoaderProgramFilePath);
            XmlDataUtil.UpdateAttribute(ref xDoc, xNode, "ConnectionString", this.ConnectionString);
            XmlDataUtil.UpdateAttribute(ref xDoc, xNode, "TableName", this.TableName);
            XmlDataUtil.UpdateAttribute(ref xDoc, xNode, "SrcDataFilePath", this.SrcDataFilePath);
            XmlDataUtil.UpdateAttribute(ref xDoc, xNode, "FieldDelimiter", ((int) this.FieldDelimiter).ToString());
            XmlDataUtil.UpdateAttribute(ref xDoc, xNode, "SrcConnStr", this.SrcConnStr);
            XmlDataUtil.UpdateAttribute(ref xDoc, xNode, "SelectSqlStatement", this.SelectSqlStatement);
            XmlDataUtil.UpdateAttribute(ref xDoc, xNode, "TrucateTargetTableBeforeLoad", this.TruncateTableBeforeInsert.ToString());

            if(this.FieldSizes !=null && this.FieldSizes.Count>0)
            {
                XmlNode fieldSizeRootNode = XmlDataUtil.AddElement(ref xDoc, xNode, "FieldSizes");
                foreach(string fieldName in this.FieldSizes.Keys)
                {
                    XmlNode fieldSizeNode = XmlDataUtil.AddElement(ref xDoc, fieldSizeRootNode, "FieldSize");
                    XmlDataUtil.UpdateAttribute(ref xDoc, fieldSizeNode,"FieldName",fieldName);
                    XmlDataUtil.UpdateAttribute(ref xDoc,fieldSizeNode,"FieldSize",this.FieldSizes[fieldName].ToString());
                }
            }
            if (this.TableFields != null && this.TableFields.Count > 0)
            {
                XmlNode fieldRootNode = XmlDataUtil.AddElement(ref xDoc, xNode, "Fields");
                foreach (string fieldName in this.TableFields)
                {
                    XmlNode fieldNode = XmlDataUtil.AddElement(ref xDoc, fieldRootNode, "Field");
                    XmlDataUtil.UpdateAttribute(ref xDoc, fieldNode, "FieldName", fieldName);
                }
            }

            return xNode;
        }

        public override InstructionBase Instantiate(XmlNode xNode)
        {
            if (xNode.Attributes.GetNamedItem("Type").Value == this.GetType().FullName)
            {
                OracleBulkLoadInstruction instruction = new OracleBulkLoadInstruction();
                instruction.OwnerComponentID = new Guid(xNode.Attributes.GetNamedItem("ComponentID").Value);
                instruction.OwnerWorkerInstanceID = new Guid(xNode.Attributes.GetNamedItem("WorkerID").Value);
                instruction.SubmitTime = DateTime.Parse(xNode.Attributes.GetNamedItem("SubmitTime").Value);
                instruction.StartTime = DateTime.Parse(xNode.Attributes.GetNamedItem("StartTime").Value);

                instruction.SqlLoaderProgramFilePath = xNode.Attributes.GetNamedItem("SqlldrFilePath").Value;
                instruction.ConnectionString = xNode.Attributes.GetNamedItem("ConnectionString").Value;
                instruction.TableName = xNode.Attributes.GetNamedItem("TableName").Value;
                instruction.SrcDataFilePath = xNode.Attributes.GetNamedItem("SrcDataFilePath").Value;
                instruction.FieldDelimiter =
                    (FieldDelimiter) int.Parse(xNode.Attributes.GetNamedItem("FieldDelimiter").Value);
                instruction.SrcConnStr = XmlDataUtil.GetAttributeValue(xNode, "SrcConnStr", "");
                instruction.SelectSqlStatement = XmlDataUtil.GetAttributeValue(xNode, "SelectSqlStatement", "");
                instruction.TruncateTableBeforeInsert = bool.Parse(XmlDataUtil.GetAttributeValue(xNode, "TruncateTargateTableBeforeLoad", false.ToString()));

                instruction.FieldSizes = null;
                XmlNodeList fieldSizeNodes = xNode.SelectNodes("FieldSizes/FieldSize");
                if(fieldSizeNodes!=null && fieldSizeNodes.Count>0)
                {
                    instruction.FieldSizes=new Dictionary<string, int>();
                    foreach(XmlNode fieldSizeNode in fieldSizeNodes)
                    {
                        string fieldName = fieldSizeNode.Attributes.GetNamedItem("FieldName").Value;
                        int fieldSize = int.Parse(fieldSizeNode.Attributes.GetNamedItem("FieldSize").Value);
                        instruction.FieldSizes.Add(fieldName,fieldSize);
                    }
                }
                XmlNodeList fieldNodes = xNode.SelectNodes("Fields/Field");
                instruction.TableFields = null;
                if(fieldNodes !=null && fieldNodes.Count>0)
                {
                    instruction.TableFields=new List<string>();
                    foreach(XmlNode fieldNode in fieldNodes)
                    {
                        instruction.TableFields.Add(fieldNode.Attributes.GetNamedItem("FieldName").Value);
                    }
                }

                return instruction;
            }
            else
            {
                throw new Exception("Unable to instantiate instruction: invalid type specified in xml node");
            }
        }
    }
}
